package com.dycong.common.threadUtil;

import com.dycong.common.Lamda.anno.CustomLambda;

import java.util.Collections;
import java.util.Set;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Created By dycong Duke on 2016/12/7.
 */
public class Lambda {

    /**
     * todo 通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码，就可以很方便地写出高性能的并发程序。所以说，Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物。
     */

    /**
     * todo public interface Function<T, R>：接口接受两个泛型类型<T, R>, T 入参类型, R 返回值类型(有输入有返回值)
     * todo public interface Supplier<T>：传入一个泛型参数T,用作返回值类型(无输入有返回值)
     * todo public interface Consumer<T>：接口接受一个泛型<T>, 接口方法是入参类型为T, 无返回值(有输入无返回值)
     * todo Predicate接口接受一个泛型<T>, 接口方法的入参类型是T, 返回值是一个布尔值(有输入有返回值Boolean)
     */

    /*public interface Function<T, R> :接口接受两个泛型类型<T, R>, T 入参类型, R 返回值类型*/
    Function<Integer, String> function = (x) -> "result: " + x;

    Function<String, String> function1 = (x) -> {
        return "String: " + x;
    };

    Function<String, String> function2 = (x) -> {
        StringBuffer str = new StringBuffer();
        str.append("after");
        str.append(x);
        return str.toString();
    };

    Function<String, String> function3 = new Function<String, String>() {
        @Override
        public String apply(String s) {
            StringBuffer str = new StringBuffer();
            str.append("after");
            str.append(s);
            return str.toString();
        }
    };


    public void testFunction() {
        System.out.println(function.apply(6));
        System.out.println(function1.apply("0"));

        /*after：t->function->function2(function的return值)*/
        System.out.println(function.andThen(function2).apply(6));

        /*before：t->function->function2(function的return值)*/
        System.out.println(function2.compose(function).apply(6));
    }



/*public interface Supplier<T>:传入一个泛型参数T,用作返回值类型*/
    /**
     *todo 这Supplier到底能用在哪呢? Java 8里新增了一个异步线程的类: CompletableFuture,
     *todo 里面的很多方法的入参都用到的Supplier, 例如: supplyAsync方法. 本文暂时不介绍CompletableFuture.
     *todo 例子，LotteryService：threadPoolService.submit(() -> sendMsg(String.valueOf(phone), String.valueOf(voucherNumber), prizeName));
     *todo Callable标有@FunctionalInterface都可以用Lambda表达式
     * 可以用（）->{}
     */
    Supplier<String> supplier = () -> "supplier";

    Supplier<String> supplier1 = () -> {
        return "supplier1";
    };

    Supplier<String> supplier2 = () -> {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("supplier2");
        return stringBuffer.toString();
    };

    Supplier<String> supplier3 = new Supplier<String>() {
        @Override
        public String get() {
            return "supplier3";
        }
    };

    public void testSupplier() {
        System.out.println(supplier.get());
    }

    /*现在了解了: 接口接受一个泛型<T>, 接口方法是入参类型为T, 无返回值*/
    Consumer<String> consumer = (x) -> System.out.println(x);

    Consumer<String> consumer1 = (x) -> {
        System.out.println(" after consumer 1" + x);
    };
    Consumer<String> consumer2 = new Consumer<String>() {
        @Override
        public void accept(String s) {
            System.out.println(" after consumer 1" + s);
        }
    };

    public void testConsumer() {
        /*after：t->function->function2(function的return值)*/
        consumer.andThen(consumer1).accept("test consumer1");
    }

    /*Predicate接口接受一个泛型<T>, 接口方法的入参类型是T, 返回值是一个布尔值*/
    Predicate<String> predicate = (x) -> x.length() > 0;
    Predicate<String> predicate1 = (x) -> {
        return x.length() > 0;
    };
    Predicate<String> predicate2 = (x) -> {
        String tmp = "asd";
        return x.length() > tmp.length();
    };

    public void testPredicate() {
        System.out.println(predicate.test("String"));
        System.out.println(predicate.and(predicate1).test("123456"));
        System.out.println(predicate.negate().test("asd"));
    }

    /**
     * @param <T> the type of input elements to the reduction operation
     * @param <A> the mutable accumulation type of the reduction operation (often
     * hidden as an implementation detail)
     * @param <R> the result type of the reduction operation
     */
    /**
     *todo supplier：这个方法主要是生成一个初始容器，用于存放转换的数据。它返回一个Supplier<A>类型，用Lambda表示为() -> A
     *todo accumulator: 这个方法是将初始容器与Stream中的每个元素进行计算，它返回一个BiConsumer<A, T>类型，用Lambda表示为(A, T) -> void
     *todo combiner: 这个方法用于在并发Stream中，将多个容器组合成一个容器，它返回一个BinaryOperator<A>类型，用Lambda表示为(A, A) -> A
     *todo finisher：这个方法用于将初始容器转换成最终的值，它返回一个Function<A, R>类型，用Lambda表示为A -> R
     *todo characteristics: 这个方法返回该Collector具有的哪些特征，返回的是一个Set, 分别是CONCURRENT(并发), UNORDERED(未排序)，IDENTITY_FINISH(finisher方法直接返回初始容器)等特征的组合。
     */
    Collector<CharSequence, String, String> collector = new Collector() {
        @Override
        public Supplier<StringBuffer> supplier() {              /*supplier方法返回一个StringBuilder对象，用于表示初始容器。*/
            return StringBuffer::new;
        }

        @Override
        public BiConsumer<StringBuffer, CharSequence> accumulator() {           /*accumulator方法返回的是StringBuilder的append方法的方法引用， 用于将Stream中的元素加入到初始容器StringBuilder中。*/
            return StringBuffer::append;
        }

        @Override
        public BinaryOperator<StringBuffer> combiner() {                /*combiner方法用于将多个StringBuilder("并发进行时")容器通过append方法组合成一个StringBuilder对象。*/
            return StringBuffer::append;
        }

        @Override
        public Function<StringBuffer, CharSequence> finisher() {        /*finisher方法是将StringBuilder对象通过toString方法最终转换成String对象。*/
            return StringBuffer::toString;
        }

        @Override
        public Set<Characteristics> characteristics() {
            return Collections.EMPTY_SET;
        }

        /*Collectors中toSet,toMap,toList使用的finisher，就一个类型转换*/
        private <I, R> Function<I, R> castingIdentity() {
            return i -> (R) i;
        }
    };


    public void testCollectors() {
        System.out.println(Stream.of("a", "b", "c", "d", "e", "f").collect(Collectors.joining()));
        System.out.println(Stream.of("a", "b", "c", "d", "e", "f").collect(Collectors.toList()));
        System.out.println(Stream.of("a", "b", "c", "d", "e", "f").collect(collector));
    }

    /**
     * Predicate -- 传入一个参数，返回一个bool结果， 方法为boolean test(T t)
     * Consumer -- 传入一个参数，无返回值，纯消费。 方法为void accept(T t)
     * Function -- 传入一个参数，返回一个结果，方法为R apply(T t)
     * Supplier -- 无参数传入，返回一个结果，方法为T get()
     * UnaryOperator -- 一元操作符， 继承Function,传入参数的类型和返回类型相同。
     * BinaryOperator -- 二元操作符， 传入的两个参数的类型和返回类型相同， 继承BiFunction
     */


    public void testCustomLambda() {
        Consumer<String> consumer = (x) -> {
            System.out.println("test" + x);
        };
        /*此x为接口方法testCustomFunction(Consumer<T> cunsumer)传入的cunsumer，所以有accept()方法，testCustomFunction方法有返回值:T*/
        CustomLambda<String> customLamda = (x) -> {
            x.accept("6");
            return "6";
        };
        System.out.println(customLamda.testCustomFunction(consumer));
    }
}
